# utils.py

import pandas as pd
import random
from numbers import Real
from typing import Union, Optional, Sequence
from typing import Union, Tuple, List
import random
def date_handler(date_str, offset_days=0):
    import pandas as pd
    date = pd.to_datetime(date_str) + pd.Timedelta(days=offset_days)
    return date.strftime("%Y年%m月%d日")  # 转换为字符串
def random_number(min_val, max_val):
    def handler(p):
        return random.randint(min_val, max_val)
    return handler

def build_key(sheet_name, field_name):
    return (sheet_name, field_name)

def generate_random_data(
    frequency: int,
    range_param: list[Real],
    base: Real = 0,
    scale: Real = 1,  # 新增缩放系数参数
    decimal: Optional[int] = None,
    as_string: bool = False
) -> Union[Sequence[Union[int, float]], str]:
    """
    生成带基值叠加的随机数据（新增缩放功能）

    :param frequency: 生成次数（必须大于0的整数）
    :param range_param: 范围参数（包含两个数字的列表）
    :param base: 基值（默认0，会加到每个结果）
    :param scale: 缩放系数（默认1，先乘以随机数再叠加基值）
    :param decimal: 小数位数（None不处理，0则取整）
    :param as_string: 是否返回字符串（默认False）

    :return: 随机数列表/字符串，格式：(基值 + 范围随机数 × 缩放系数)
    """
    if not isinstance(scale, Real):
        raise TypeError("缩放系数必须是数字类型")

    if not isinstance(frequency, int) or frequency <= 0:
        raise TypeError("生成次数必须为大于0的整数")
    
    if not (isinstance(range_param, list) and len(range_param) == 2):
        raise ValueError("范围参数格式错误，请使用：[起始值, 结束值]")
    
    if not all(isinstance(x, Real) for x in range_param):
        raise TypeError("范围参数必须包含数字类型元素")
    
    if not isinstance(base, Real):
        raise TypeError("基值必须是数字类型")
    
    if decimal and not isinstance(decimal, int):
        raise TypeError("小数位数必须是整数")

    start, end = sorted(map(float, range_param))
    numbers = [
        (random.uniform(start, end) * scale) + base
        for _ in range(frequency)
    ]
    
    if decimal is not None:
        numbers = [round(float(num), decimal) for num in numbers]
        if decimal == 0:
            numbers = [int(float(num)) for num in numbers]
    
    if as_string:
        fmt_func = lambda x: f"{x}" if decimal is None else f"{x:.{decimal}f}"
        return "、".join(fmt_func(num) for num in numbers)
    print(numbers)
    return numbers

def calculate_rectangle_coords(
    start_point: Union[Tuple[float, float], List[float]],
    width: float,
    height: float
) -> List[Tuple[float, float]]:
    """
    根据起点坐标、宽度和高度计算长方形四个顶点坐标
    
    :param start_point: 起点坐标 (x, y)
    :param width: 横向长度（正数向右延伸，负数向左延伸）
    :param height: 纵向高度（正数向上延伸，负数向下延伸）
    :return: 按顺时针顺序排列的四个顶点坐标列表
    
    示例：
    >>> calculate_rectangle_coords((0, 0), 3, 2)
    [(0, 0), (3, 0), (3, 2), (0, 2)]
    
    >>> calculate_rectangle_coords((2, 5), -1, 3)
    [(2, 5), (1, 5), (1, 8), (2, 8)]
    """
    if not isinstance(start_point, (tuple, list)) or len(start_point) != 2:
        raise ValueError("起点坐标格式错误，应为包含两个数值的元组或列表")
    
    if not all(isinstance(coord, (int, float)) for coord in start_point):
        raise TypeError("坐标值必须为整数或浮点数")
    
    if not isinstance(width, (int, float)):
        raise TypeError("宽度必须为数值类型")
    
    if not isinstance(height, (int, float)):
        raise TypeError("高度必须为数值类型")

    start_x, start_y = start_point
    return [
        (start_x, start_y),
        (start_x + width, start_y),
        (start_x + width, start_y + height),
        (start_x, start_y + height)
    ]

def date_offset_handler(days_offset=0):
    def handler(p):
        base_date = pd.to_datetime(p['project_info']['施工日期'])
        return base_date + pd.Timedelta(days=days_offset)
    return handler

def random_int(min_val, max_val):
    return lambda _:  random.randint(min_val, max_val)

# utils/date_utils.py
from datetime import datetime, timedelta


def parse_date(date_str):
    return datetime.strptime(date_str, "%Y/%m/%d")


def format_date(dt, fmt="%Y年%m月%d日"):
    return dt.strftime(fmt)


def date_offset_handler2(namespace, base_field, offset_days):
    def handler(project_info):
        full_key = f"{namespace}.{base_field}" if namespace else base_field
        base_date_str = project_info.get(full_key)
        if not base_date_str:
            raise ValueError(f"缺少基准字段：{full_key}")
        base_date = parse_date(base_date_str)
        offset_date = base_date + timedelta(days=offset_days)
        return format_date(offset_date)

    return handler
def generate_random_data_with_params(**kwargs):
    def handler(p):
        return generate_random_data(**kwargs)
    return handler